package edu.kit.aifb.ldstream.cli;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.openrdf.model.vocabulary.RDFS;
import org.openrdf.repository.RepositoryException;
import org.openrdf.repository.sail.SailRepository;
import org.openrdf.rio.RDFFormat;

import org.openrdf.sail.inferencer.fc.ForwardChainingRDFSInferencer;
import org.openrdf.sail.memory.MemoryStore;
import org.openrdf.sail.nativerdf.NativeStore;

import joptsimple.OptionParser;
import joptsimple.OptionSet;

import edu.kit.aifb.ldstream.env.Environment;
import edu.kit.aifb.ldstream.learner.Learner;
import edu.kit.aifb.ldstream.repository.RepositoryBuilder;



/**
 * Class for starting the listener & learner.
 * 
 * Starting the listener & learner after initializing global variables needed for the computation.
 * 
 * @author Holger
 *
 */
public class CLI {

	private static final String C = "c";
	private static final String V = "v";
	private static final String R = "r";
	
	/**
	 * Used to start Listener & the Learner.
	 * 
	 * @param args Starter options, the following are available
	 *        <ul>
	 *        	<li> -c Path of the configuration file </li>
	 *        	<li> -r Path of the repository file </li>
	 *        	<li> -v Verbose mode </li>
	 *        </ul>
	 *        
	 */
	public static void main(String[] args) {
		
		// Reading args and initializing repository
		init(args);
		
		//Testing
		
		ExecutorService threadPool = Executors.newCachedThreadPool();
		
	//	RepositoryBuilder rbuilder = new RepositoryBuilder(2, threadPool);
	//	rbuilder.addFile("./ressources/household0.n3", "http://people.aifb.kit.edu/awa/2011/smartgrid/",RDFFormat.N3);
		//rbuilder.addFile("./ressources/household0.n3", "http://people.aifb.kit.edu/awa/2011/smartgrid/",RDFFormat.N3);
		//	rbuilder.addFile("./ressources/household1.n3", "http://people.aifb.kit.edu/awa/2011/smartgrid/");
		
		
		String stream = "http://people.aifb.kit.edu/awa/2011/smartgrid/schema/informationexchange#";
		String baseURI = "http://people.aifb.kit.edu/awa/2011/smartgrid/";
		
		String stream2 = "http://harth.org/andreas/foaf.rdf";
		String baseURI2= "http://harth.org/andreas/foaf#";
	//	rbuilder.addStream(stream, baseURI, 10000);
		/*
		
		rbuilder.start();
		
		try {
			rbuilder.join();
		} catch (InterruptedException e1) {}
		
		*/
		Learner learner = new Learner(threadPool);
		learner.learn();
		
		threadPool.shutdown();
		shutdown();

		
	}
	
	private static void shutdown(){
		try {
			Environment.REPO.shutDown();
		} catch (RepositoryException e) {
			e.printStackTrace();
		}
	}
	
	private static void init(String[] args){
		//loading options
		OptionParser op = new OptionParser();
		op.accepts(C, "Path of the configuration file").withRequiredArg().ofType(String.class);
		op.accepts(R, "Path of the repository").withRequiredArg().ofType(String.class);
		op.accepts(V, "Verbose mode");
		OptionSet os = op.parse(args);
		
		if(os.has(V)){
			Environment.VERBOSE = true;
		}
		if (os.has(C)){
			Environment.s_configPath = (String)os.valueOf(C);
		}else { // standard path
			Environment.s_configPath = "./config/config.prop";
		}
		
		Properties prop = new Properties();
		File configFile = new File(Environment.s_configPath);
		String repoPath = "";
		// if config file already exists load it
		if(configFile.exists()){
			try {
				if(os.has(R)){
					prop.setProperty(Environment.REPOPATH_PROPERTY, (String) os.valueOf(R));
				}
				prop.load(new FileReader(new File(Environment.s_configPath)));
			} catch (FileNotFoundException e) {
				System.err.println("Could not find config file");
				e.printStackTrace();
			} catch(IOException e){
				e.printStackTrace();
			}
			repoPath = prop.getProperty(Environment.REPOPATH_PROPERTY);
			
		// if config file does not exist create it and write the repository path into it
		}else{
			FileWriter fr = null;
			try{
				configFile.createNewFile();
				if(Environment.VERBOSE){
					System.out.println("New config file created at " + configFile.getAbsolutePath() );
				}
				fr = new FileWriter(configFile);
				if(os.has(R)){
					repoPath = (String)os.valueOf(R);
					fr.write(Environment.REPOPATH_PROPERTY + "=" + repoPath);
					fr.flush();
				}else{
					repoPath = "./repository/";
					fr.write(Environment.REPOPATH_PROPERTY + "=" + repoPath);
					fr.flush();
				}
			}catch(IOException e){
				e.printStackTrace();
			}
			try {
				if(fr != null){
					fr.close();
				}
			} catch (IOException e) {
				System.err.println("Could not close FileWriter");
				e.printStackTrace();
			}
		}
		
		
		// declare and initialize Sesame repository
		initializeRepository(repoPath);
	}
	
	
	private static void initializeRepository(String repoPath){
				File repoFile = new File(repoPath);
				Environment.REPO = new SailRepository(new ForwardChainingRDFSInferencer(new NativeStore(repoFile,"psoc,opsc,spoc")));
				try {
					Environment.REPO.initialize();
				} catch (RepositoryException e) {
					System.err.println("Could not initialize repository");
					e.printStackTrace();
				}
				if(Environment.VERBOSE){
					System.out.println("Repository initialized at: " + repoFile.getAbsolutePath());
				}
	}

}
